﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.Threading.Tasks;

namespace FrogEngine
{
	public class KeyboardInputService : GameEntityServiceBase<IHandlesKeyboardInput>, IKeyboardInputService
	{
		public KeyboardInputService(IEngine engine)
			: base(engine)
		{
			serviceOrder = 1;
			currentStates = new Dictionary<PlayerIndex, KeyboardState>();
			previousStates = new Dictionary<PlayerIndex, KeyboardState>();

			currentStates.Add(PlayerIndex.One, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.One));
			currentStates.Add(PlayerIndex.Two, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Two));
			currentStates.Add(PlayerIndex.Three, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Three));
			currentStates.Add(PlayerIndex.Four, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Four));

			previousStates.Add(PlayerIndex.One, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.One));
			previousStates.Add(PlayerIndex.Two, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Two));
			previousStates.Add(PlayerIndex.Three, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Three));
			previousStates.Add(PlayerIndex.Four, Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Four));
		}

		private Dictionary<PlayerIndex, KeyboardState> currentStates;
		public IDictionary<PlayerIndex, KeyboardState> CurrentStates
		{
			get { return currentStates; }
		}

		private Dictionary<PlayerIndex, KeyboardState> previousStates;
		public IDictionary<PlayerIndex, KeyboardState> PreviousStates
		{
			get { return previousStates; }
		}

		public override bool Subscribe(IGameEntity entity)
		{
			if (base.Subscribe(entity))
				return true;
			else
				throw new EntityCompatibilityException(entity.GetType(), this.GetType());
		}

		public override bool Unsubscribe(IGameEntity entity)
		{
			return base.Unsubscribe(entity);
		}

		public void Update(GameTime gameTime)
		{
			if (isPaused)
				return;

			currentStates[PlayerIndex.One] = Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.One);
			currentStates[PlayerIndex.Two] = Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Two);
			currentStates[PlayerIndex.Three] = Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Three);
			currentStates[PlayerIndex.Four] = Keyboard.GetState(Microsoft.Xna.Framework.PlayerIndex.Four);

#if WINDOWS
			Parallel.ForEach(subscribedEntities.Cast<IHandlesKeyboardInput>(), new Action<IHandlesKeyboardInput>(a =>
			{
				if (a.PlayerIndex.HasFlag(PlayerIndex.One))
					a.HandleInput(gameTime, PlayerIndex.One, CurrentStates[PlayerIndex.One], PreviousStates[PlayerIndex.One]);
				if (a.PlayerIndex.HasFlag(PlayerIndex.Two))
					a.HandleInput(gameTime, PlayerIndex.Two, CurrentStates[PlayerIndex.Two], PreviousStates[PlayerIndex.Two]);
				if (a.PlayerIndex.HasFlag(PlayerIndex.Three))
					a.HandleInput(gameTime, PlayerIndex.Three, CurrentStates[PlayerIndex.Three], PreviousStates[PlayerIndex.Three]);
				if (a.PlayerIndex.HasFlag(PlayerIndex.Four))
					a.HandleInput(gameTime, PlayerIndex.Four, CurrentStates[PlayerIndex.Four], PreviousStates[PlayerIndex.Four]);
			}));
#else
			foreach (var entity in subscribedEntities.Cast<IHandlesKeyboardInput>())
				entity.HandleInput(gameTime, CurrentStates[entity.PlayerIndex], PreviousStates[entity.PlayerIndex]);
#endif

			previousStates[PlayerIndex.One] = currentStates[PlayerIndex.One];
			previousStates[PlayerIndex.Two] = currentStates[PlayerIndex.Two];
			previousStates[PlayerIndex.Three] = currentStates[PlayerIndex.Three];
			previousStates[PlayerIndex.Four] = currentStates[PlayerIndex.Four];
		}

		#region { IPausable ]
		private bool isPaused = false;
		public void Pause()
		{
			isPaused = true;
		}

		public void Resume()
		{
			isPaused = false;
		}
		#endregion
	}
}
